home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / simcode.arc / COM.ASM < prev    next >
Encoding:
Assembly Source File  |  1984-12-12  |  19.0 KB  |  772 lines

  1.     Title    COM - Interrupt Driven Communications Software
  2.     Page    86,132
  3.     include struct.mac
  4. ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  5. ;:                                    ::
  6. ;:    Copyright, 1982,  University of B.C.  Computing Centre        ::
  7. ;:                                    ::
  8. ;:    Permission to copy  without fee  all  or  part of this        ::
  9. ;:    material  is  granted  provided  that  copies  are not        ::
  10. ;:    made  or  distributed  for direct commercial advantage,     ::
  11. ;:    and that this copyright notice is retained in the copy.     ::
  12. ;:                                    ::
  13. ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  14.  
  15.  
  16. ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  17. ;:                                    ::
  18. ;:   Modified for use with SIMTERM and PASCAL calling sequences     ::
  19. ;:   Functions added for controlling and examining line status.     ::
  20. ;:   Modified to use the 'structured' macros for easier reading.    ::
  21. ;:                                    ::
  22. ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  23.  
  24.     Name    DRIVERS
  25.  
  26.     ;8250 Asynchronous Communications Element - Registers
  27.     ;  The following EQUs assume that the base address is
  28.     ;  in BX.
  29.  
  30. DLH    EQU    [bx+1]        ;Divisor Latch High byte
  31. DLL    EQU    [bx]        ;Divisor Latch Low  byte
  32. IER    EQU    [bx+1]        ;Interrupt Enable Register
  33. IIR    EQU    [bx+2]        ;Interrupt Identification Register
  34. IOR    EQU    [bx]        ;Input Output Register
  35. LCR    EQU    [bx+3]        ;Line Control Register
  36. LSR    EQU    [bx+5]        ;Line Status  Register
  37. MCR    EQU    [bx+4]        ;Modem Control Register
  38. MSR    EQU    [bx+6]        ;Modem Status  Register
  39.  
  40. rs232_base equ    400H        ;address of rs232 adapters
  41.  
  42.     ;8259A Priority Interrupt Controller - Registers
  43.  
  44. INTA0    EQU    20H        ;Register 0
  45. INTA1    EQU    21H        ;Register 1
  46.  
  47.     ;8259A Priority Interrupt Controller - Commands
  48.  
  49. EOI    EQU    20H        ;Non-specific EOI
  50. timer_low equ    es:[46CH]    ; low word of timer
  51.  
  52.     ;COM Flags Mask Bits
  53.  
  54. F_T_ACT EQU    00000001B    ;Transmitter Active
  55. ;F_BREAK EQU     00000010B     ;Break sequence started
  56. F_XCONT EQU    00000100B    ;XON/XOFF control enabled
  57. F_XOFFR EQU    00001000B    ;XOFF recieved/don't transmit
  58. F_XOFFT EQU    00010000B    ;XOFF transmitted/drain buffer
  59. F_SXOFF EQU    00100000B    ;Send XOFF
  60. F_SXON    EQU    01000000B    ;Send XON
  61.  
  62.     ;Constants
  63.  
  64. RBUF_SIZE EQU    3000        ;Receive buffer size
  65. FENCE_1 EQU    rbuf_size/4    ;Send XON fence
  66. FENCE_2 EQU    1000        ;Send XOFF fence
  67. SET_BRK EQU    01000000B    ;Set-Break flag of LCR
  68. thre    equ    00100000b    ; THRE in LSR
  69. XOFF    EQU    00010011B    ;ASCII DC3
  70. XON    EQU    00010001B    ;ASCII DC1
  71.  
  72.     ;ERR_FLAG masks
  73.  
  74. chg_lsr equ      00001B       ; change in LSR
  75. chg_msr equ      00010B       ; change in MSR
  76. buf_ful equ      00100B       ; receive buffer full
  77. trans_error equ   01000B       ; got an xmit interrupt when we should not have
  78. not_xmitted equ   10000B       ; could not transmit character
  79.  
  80. data    segment public 'data'
  81.     public    err_flag
  82. err_flag db    0        ; record any error conditions
  83.     public    lsr_value
  84. lsr_value db    ?        ; LSR at change
  85.     public    msr_value
  86. msr_value db    ?        ; MSR at change
  87.     public    recv_reset
  88. recv_reset db    0        ; flag to reset receiver buffer on BREAK
  89. data    ends
  90. dgroup    group    data
  91.  
  92. Communications    SEGMENT PARA PUBLIC 'CODE'
  93.  
  94. com_base dw    ?        ; base address of the Async Port
  95. irq_num db    ?        ; user specified IRQ
  96. int_base dw    ?        ; interrupt @ corresonding to IRQ
  97. ds_pascal dw    ?        ; DS on entry (PASCAL Data segment)
  98. CIVA    DW    ?        ;Comm Interrupt Vector Address
  99. CIVS    DW    ?        ;Comm Interrupt Vector Segment
  100. FLAGS    DB    ?        ;COM state Flags
  101. intr_count dw    0        ; count # of double interrupts
  102. R_INDEX DW    ?        ;Recieve buffer index pointer
  103. R_length DW     ?         ;Recieve buffer length
  104. R_BUFF    DB    rbuf_size DUP(?)     ;Recieve character Buffer
  105. r_buff_end equ    $-1
  106.  
  107.  
  108.  
  109.  
  110.     PUBLIC    COM_Begin,COM_End
  111.     PUBLIC    breaker
  112.     PUBLIC    COM_Get
  113.     PUBLIC    send
  114.  
  115. ;---------------------------------------
  116. ; Setup the interrupt code
  117. ;---------------------------------------
  118.  
  119.  
  120. COM_Begin    PROC    FAR
  121.     ASSUME    CS:Communications,DS:nothing
  122.  
  123. ;procedure COM_Begin( Port    : word;      [bp+12]  (IRQ [bp+13])
  124. ;              Speed    : word;      [bp+10]
  125. ;              LCR    : word;      [bp+8]
  126. ;              X_Control : boolean ); [bp+6]
  127.  
  128.     PUSH    BP        ;Save frame pointer
  129.     MOV    BP,SP        ;Get new frame pointer
  130.     mov    ax,ds
  131.     mov    ds_pascal,ax    ; Save DS to PASCAL data segment
  132.     push    ds
  133.     mov    ax,cs        ;setup DS addressability
  134.     mov    ds,ax
  135.     assume    ds:communications
  136.     XOR    AX,AX        ;Clear AX
  137.     MOV    ES,AX        ;Address bottom of memory
  138.     MOV    FLAGS,AL    ;Initialize state flags
  139.     MOV    R_length,AX     ;Zero Receive buffer Length
  140.     MOV    R_INDEX,OFFSET R_BUFF
  141.     mov    si,[bp+12]    ; com port #
  142.     and    si,0FFH     ; mask off the port#
  143.     shl    si,1
  144.     mov    bx,es:rs232_base[si]       ; pickup the base address
  145.     mov    com_base,bx    ; save for the rest of the program
  146.     MOV    AL,10000000B    ;Set Divisor-Latch bit
  147.     lea    dx,lcr
  148.     OUT    DX,AL        ;Write LCR
  149.     MOV    AX,[BP+10]    ;Get Bit Rate Divisor
  150.     lea    dx,dll
  151.     OUT    DX,AL        ;Write Divisor Latch Low byte
  152.     MOV    AL,AH        ;Get high part of divisor
  153.     lea    DX,DLH
  154.     OUT    DX,AL        ;Write Divisor Latch High byte
  155.  
  156.     MOV    AL,[BP+8]    ;Get Line Control Register settings
  157.     AND    AL,00111111B    ;Mask out unwanted stuff
  158.     lea    DX,LCR
  159.     OUT    DX,AL        ;Write LCR
  160.  
  161.     .if    <byte ptr [bp+6]> ne 0
  162.         OR        FLAGS,F_XCONT   ;Turn on XON/XOFF control
  163.     .endif
  164.  
  165.     mov    al,[bp+13]    ; user specified IRQ
  166.     xor    ah,ah        ; clear high byte
  167.     shl    ax,1
  168.     shl    ax,1        ; X 4
  169.     mov    si,ax
  170.     add    si,20H        ; base of 8259A interrupts
  171.     mov    int_base,si    ; save it
  172.  
  173.     CLI            ;Disable interrupts
  174.  
  175.     MOV    AX,ES:[si+2]    ;Get CIV segment
  176.     MOV    CIVS,AX     ;Save CIVS
  177.     MOV    AX,ES:[si]    ;Get CIV address
  178.     MOV    CIVA,AX     ;Save CIVA
  179.     MOV    ES:[si+2],CS    ;Patch Interrupt Vector
  180.     MOV    WORD PTR ES:[si],OFFSET COM_I
  181.  
  182.     STI            ;Enable interrupts
  183.  
  184.     MOV    AL,00001011B    ;Modem Control Register Settings
  185.     lea    DX,MCR
  186.     OUT    DX,AL        ;Write MCR
  187.  
  188.     lea    DX,MSR        ;Get address of Modem Status Register
  189.     IN    AL,DX        ;Get Modem Status
  190.  
  191.     lea    DX,LSR        ;Get address of Line Status Register
  192.     IN    AL,DX        ;Get Line Status
  193.  
  194.     lea    DX,IOR        ;Get address of I/O Register
  195.     IN    AL,DX        ;Get spurious reciever data
  196.  
  197.     MOV    AL,00001101B    ;Interrupt Enable Register Settings
  198.                 ; Don't enable the THRE interrupt
  199.     lea    DX,IER
  200.     OUT    DX,AL        ;Write IER
  201.  
  202.     mov    cl,[bp+13]    ; user specified IRQ
  203.     mov    ch,1        ; bit for mask
  204.     shl    ch,cl        ; shift mask to proper position
  205.     mov    irq_num,ch    ; save it
  206.     not    ch        ; complement
  207.     IN    AL,INTA1    ;Get IRQ mask from 8259A
  208.     AND    AL,ch        ;Mask out IRQ4 bit
  209.     OUT    INTA1,AL    ;Enable IRQ4
  210.  
  211.     pop    ds
  212.     POP    BP        ;Restore Frame Pointer
  213.     RET    8        ;Return to caller
  214.  
  215. COM_Begin    ENDP
  216.  
  217. ;---------------------------------------
  218. ; reset to original condition before exit
  219. ;---------------------------------------
  220.  
  221. COM_End     PROC    FAR
  222.  
  223. ;procedure COM_End;
  224.  
  225.     push    ds
  226.     mov    ax,cs        ;setup addressability for DS
  227.     mov    ds,ax
  228.     mov    bx,com_base
  229.     XOR    AX,AX        ;Clear AX
  230.  
  231.     lea    DX,IER
  232.     OUT    DX,AL        ;Turn off comm interrupts
  233.  
  234.     IN    AL,INTA1    ;Get 8259A IRQ mask
  235.     OR    AL,irq_num    ;Mask in IRQ4 bit
  236.     OUT    INTA1,AL    ;Disable IRQ4
  237.  
  238.     XOR    AX,AX        ;Clear AX
  239.     MOV    ES,AX        ;Address bottom of mermory
  240.  
  241.     CLI            ;Disable interrupts
  242.  
  243.     mov    si,int_base
  244.     MOV    AX,CIVS     ;Restore Comm Interrupt Vector
  245.     MOV    ES:[si+2],AX
  246.     MOV    AX,CIVA
  247.     MOV    ES:[si],AX
  248.  
  249.     STI            ;Enable interrupts
  250.  
  251.     pop    ds
  252.     RET            ;Return to caller
  253.  
  254. COM_End     ENDP
  255. ;---------------------------------------
  256. ; interrupt code
  257. ;---------------------------------------
  258.  
  259. COM_I    PROC    FAR        ;COM Interrupt service routine
  260. ;--------------------- removed to `cure' the overrun problem ------------+
  261. ;    STI            ;Allow further interrupts         |
  262. ;------------------------------------------------------------------------+
  263.     PUSH    AX
  264.     PUSH    BX
  265.     PUSH    DX
  266.     PUSH    DI
  267.     PUSH    DS
  268.  
  269.     mov    ax,cs        ;setup addressability for DS
  270.     mov    ds,ax
  271.     mov    bx,com_base
  272.     dec    intr_count
  273. ;
  274. ; loop back here to see if any move interrupts are pending
  275. ;
  276. retry:    lea    DX,IIR
  277.     IN    AL,DX        ;Get class of interrupt
  278.     .ifc    al,1 *LONG*    ; interrupt pending
  279.         inc     intr_count
  280.         xor     ah,ah        ; clear high bits
  281.         mov     di,ax
  282.         jmp     [intr_type+di]
  283.  
  284. ; --------------------
  285. ; Interuupt Jump Table
  286. ; --------------------
  287. intr_type   dw        modem_intr
  288.         dw        trans_intr        ; should not get here!!
  289.         dw        recv_intr
  290.         dw        status_intr
  291.  
  292. ; ---------------------
  293. ; LINE STATUS INTERRUPT
  294. ; ---------------------
  295. status_intr:
  296.         push    ds
  297.         mov     ax,ds_pascal
  298.         mov     ds,ax
  299.         assume  ds:dgroup
  300.         lea     DX,LSR        ;Get line status
  301.         IN        AL,DX
  302.         mov     lsr_value,al    ;save value at change
  303.         or        err_flag,chg_lsr
  304.         pop     ds
  305.         assume  ds:communications
  306.         JMP     retry
  307.  
  308. ; ----------------------------
  309. ; RECEIVE DATA READY INTERRUPT
  310. ; ----------------------------
  311. recv_intr:
  312.         lea     DX,IOR        ;Get address of I/O Register
  313.         IN        AL,DX        ;Get recieved byte
  314.         .ifs    flags,f_xcont    ; XON/XOFF control
  315.         mov    ah,al        ; mask off the parity
  316.         and    ah,7FH        ;   bit on the character
  317.         .if    ah e xoff
  318.             OR        FLAGS,F_XOFFR   ;To stop transmitter
  319.             JMP     retry
  320.         .endif
  321.  
  322.         .if    ah e xon    ; XON received
  323.             AND     FLAGS,NOT F_XOFFR        ;To release transmitter
  324.             JMP     retry
  325.         .endif
  326.  
  327.         .if    r_length g <size r_buff - fence_2> ; if recv buffer is full
  328.             .ifc    flags,f_xofft   ; and XOFF not transmitted
  329.             .ifs    flags,f_t_act    ; xmitter not active
  330.                 or        flags,f_sxoff+f_xofft    ; send XOFF
  331.             .else
  332.                 or        flags,f_xofft
  333.                 push    ax
  334.                 mov     al,xoff    ; send the XOFF character
  335.                 call    send_char
  336.                 pop     ax
  337.             .endif
  338.             .endif
  339.         .endif
  340.         .endif
  341.  
  342.         .if     r_length ge <size r_buff>     ;if buffer full, ignore character
  343.         push    ds
  344.         mov    ax,ds_pascal
  345.         mov    ds,ax
  346.         assume    ds:dgroup
  347.         or    err_flag,buf_ful
  348.         pop    ds
  349.         assume    ds:communications
  350.         jmp    retry
  351.         .endif
  352.  
  353.         MOV     DI,R_INDEX        ;Get pointer into R_BUFF
  354.         MOV     [DI],AL        ;Put new byte into buffer
  355.         INC     R_length         ;Increase buffer length by 1 byte
  356.         inc     r_index
  357.         .if     di e <offset r_buff_end>  ;check for wrap around
  358.         mov    r_index,offset r_buff
  359.         .endif
  360.         jmp     retry
  361.  
  362. ; ---------------------
  363. ; TRANSMITTER INTERRUPT   (Should never get here. If we do, exit gracefully)
  364. ; ---------------------
  365.  
  366. trans_intr:
  367.         push    ds
  368.         mov    ax,ds_pascal
  369.         mov    ds,ax
  370.         assume    ds:dgroup
  371.         or    err_flag,trans_error
  372.         pop    ds
  373.         assume    ds:communications
  374.         jmp    retry
  375.  
  376. ; ----------------------
  377. ; MODEM STATUS INTERRUPT
  378. ; ----------------------
  379. modem_intr:
  380.         push    ds
  381.         mov     ax,cs:ds_pascal
  382.         mov     ds,ax
  383.         assume  ds:dgroup
  384.         lea     DX,MSR        ;Get modem status
  385.         IN        AL,DX
  386.         mov     msr_value,al
  387.         or        err_flag,chg_msr
  388.         pop     ds
  389.         assume  ds:communications
  390.         jmp     retry        ; loop until all interrupts are cleared
  391.     .endif
  392.  
  393. ;    CLI            ;Turn off interrupts
  394.     MOV    AL,EOI        ;End Of Interrupt command
  395.     OUT    INTA0,AL    ;Signal 8259A of EOI
  396.     POP    DS
  397.     POP    DI
  398.     POP    DX
  399.     POP    BX
  400.     POP    AX
  401.     IRET
  402.  
  403. COM_I    ENDP
  404.  
  405. ;---------------------------------------
  406. ; Generate BREAK
  407. ;---------------------------------------
  408.  
  409. breaker PROC    FAR
  410.     assume    ds:nothing
  411.  
  412. ;procedure COM_Break;
  413.     mov    bx,com_base
  414.     cli            ; lock out interrupts
  415.     lea    dx,lcr
  416.     IN    AL,DX        ;Get LCR settings
  417.     OR    AL,SET_BRK    ;Set set-break flag
  418.     OUT    DX,AL        ;Start break sequence
  419.     and    flags,not f_t_act+f_xoffr    ; mark xmitter `not active'
  420.     assume    es:nothing
  421.     sti
  422.     XOR    AX,AX        ;Clear AX
  423.     mov    es,ax        ; ES points to low core
  424.     mov    ax,timer_low    ; pickup current time
  425.     .repeat         ; wait for time to expire
  426.         mov     cx,timer_low
  427.         sub     cx,ax
  428.     .until    cx a 2
  429.     cli
  430.     in    al,dx
  431.     and    al,not set_brk    ; stop the break sequence
  432.     out    dx,al
  433.     mov    ax,ds_pascal    ; setup ES->PASCAL data segment
  434.     mov    es,ax
  435.     assume    es:dgroup
  436.     .if    recv_reset ne 0
  437.         mov     r_length,0  ; reset the receiver buffer
  438.     .endif
  439.     assume    es:nothing
  440.     sti
  441.     RET            ;Return to caller
  442.  
  443. breaker ENDP
  444.  
  445.  
  446. ;---------------------------------------
  447. ; clear the receiver buffer
  448. ;---------------------------------------
  449.     public    clear_receiver
  450. clear_receiver proc    far
  451.     assume ds:nothing
  452.     mov    ax,ds_pascal
  453.     mov    es,ax
  454.     assume    es:dgroup
  455.     .if    recv_reset ne 0
  456.         cli
  457.         mov        r_length,0        ; clear the recv buffer
  458.         sti
  459.     .endif
  460.     assume    es:nothing
  461.     ret
  462. clear_receiver endp
  463.  
  464. ;---------------------------------------
  465. ; Get character from receive buffer
  466. ;---------------------------------------
  467.  
  468. COM_Get     PROC    FAR
  469.     assume    ds:nothing
  470.  
  471. ;function COM_Get( var Character : char ) : boolean
  472.  
  473.     .if    r_length le 0     ; receive buffer is empty
  474.         MOV     AX,1        ;Return buffer empty code to caller
  475.         RET     2
  476.     .endif
  477.  
  478.     PUSH    BP        ;Save frame pointer
  479.     MOV    BP,SP        ;Get new frame pointer
  480.  
  481.     push    ds
  482.     mov    ax,ds        ;setup ES to point to PASCAL data space
  483.     mov    es,ax
  484.  
  485.     mov    ax,cs        ;setup addressability for DS
  486.     mov    ds,ax
  487.     assume    ds:communications
  488.     mov    bx,com_base
  489.     CLI            ;Disable interrupts
  490.     MOV    SI,R_INDEX    ;Get pointer into recieve buffer
  491.     SUB    SI,R_length     ;Subtract length of buffer
  492.     .if    si l <offset r_buff>    ; check if pointer needs adjustment
  493.         add     si,size r_buff
  494.     .endif
  495.  
  496.     MOV    AL,[SI]     ;Get character from buffer
  497.     DEC    R_length     ;Reduce size of buffer by 1 byte
  498.     MOV    DI,[BP+6]    ;Get address of parameter
  499.     MOV    es:[DI],AL    ;Store result of COM Get
  500.     .ifs    flags,f_xcont    ;XON/XOFF control specified
  501.         .ifs    flags,f_xofft    ;XOFF was transmitted
  502.         .if    r_length le fence_1     ;buffer is below the low water mark
  503.             AND     FLAGS,NOT F_XOFFT        ;Clear XOFF-transmitted flag
  504.             call    set_active    ; set XMIT active
  505.             mov     al,xon    ; send XON
  506.             call    send_char
  507.             call    clear_active    ; clear XMIT active
  508.         .endif
  509.         .endif
  510.     .endif
  511.  
  512.     XOR    AX,AX        ;Return O.K. code to caller
  513.     STI            ;Enable interrupts
  514.     pop    ds
  515.     POP    BP        ;Restore frame pointer
  516.     RET    2        ;Return to caller
  517.  
  518. COM_Get     ENDP
  519.  
  520.  
  521. ;---------------------------------------
  522. ; Send a character
  523. ;---------------------------------------
  524.  
  525. send    PROC    FAR
  526.  
  527. ;function send( Buffer : lstring ) : integer;
  528. ;        8-size, 6-@
  529.  
  530.     PUSH    BP        ;Save frame pointer
  531.     MOV    BP,SP        ;Get new frame pointer
  532.     mov    ax,ds        ;save DS in ES
  533.     mov    es,ax
  534.     push    ds
  535.     mov    ax,cs        ;setup addressability for DS
  536.     mov    ds,ax
  537.     assume    ds:communications
  538.     mov    bx,com_base
  539.     MOV    CX,[BP+8]    ;Get length of string to write
  540.     .if    cx g 0
  541.         mov     si,[bp+6]        ; @ of output string
  542.         .repeat
  543.         call    set_active
  544.         mov    al,es:[si]  ; pickup data from PASCAL
  545.         call    send_char
  546.         inc    si
  547.         call    clear_active
  548.         .until loop
  549.     .endif
  550.     mov    ax,-1        ; return OK status
  551.     pop    ds
  552.     POP    BP        ;Restore frame pointer
  553.     RET    4        ;Return to caller
  554.  
  555. send    ENDP
  556.  
  557. ;---------------------------------------
  558. ; Set the transmitter active flag
  559. ;---------------------------------------
  560. set_active proc near
  561.     cli
  562.     or    flags,f_t_act
  563.     sti
  564.     ret
  565. set_active endp
  566.  
  567.  
  568. ;---------------------------------------
  569. ; clear the xmit active flag and check for special conditions
  570. ;---------------------------------------
  571. clear_active proc near
  572.     cli
  573.     .ifs    flags,f_sxoff        ; should we send an XOFF
  574.         and     flags,not f_sxoff
  575.         sti
  576.         push    ax
  577.         mov     al,xoff
  578.         call    send_char
  579.         pop     ax
  580.         jmp     clear_active    ; try again
  581.     .endif
  582.     and    flags,not f_t_act
  583.     sti
  584.     ret
  585. clear_active endp
  586.  
  587. ;---------------------------------------
  588. ; Send a character (checking for time outs and such)
  589. ;---------------------------------------
  590. wait_count equ    36        ; wait at most 2 seconds
  591. send_char proc    near
  592.     push    cx
  593.     push    dx
  594.     .ifs    flags,f_xoffr        ; check for xmit hold
  595.         xor     cx,cx
  596.         mov     es,cx            ; address low core for the timer
  597.         mov     dx,timer_low        ; pickup current time
  598.         .repeat
  599.         .ifc    flags,f_xoffr    ; terminate if cleared
  600.             mov     cx,wait_count+1
  601.         .else
  602.             mov     cx,timer_low
  603.             sub     cx,dx
  604.         .endif
  605.         .until  cx a wait_count    ; wait at most 2 seconds
  606.         and     flags,not f_xoffr    ; clear the wait flag and just proceed
  607.     .endif
  608.     xor    cx,cx            ; setup wait counter
  609.     lea    dx,lsr
  610.     mov    ah,al            ; save character to xmit
  611.     .repeat
  612.         in        al,dx
  613.         .ifs    al,thre        ; THRE is empty
  614.         mov    al,ah
  615.         lea    dx,ior
  616.         out    dx,al
  617.         pop    dx
  618.         pop    cx
  619.         ret
  620.         .endif
  621.     .until loop
  622.     push    ds
  623.     mov    ax,ds_pascal
  624.     mov    ds,ax
  625.     assume    ds:dgroup
  626.     or    err_flag,not_xmitted
  627.     pop    ds
  628.     assume    ds:communications
  629.     pop    dx
  630.     pop    cx
  631.     ret
  632. send_char endp
  633.  
  634.  
  635. ;---------------------------------------
  636. ; get/set XON/XOFF status
  637. ;---------------------------------------
  638.  
  639. ;
  640. ; function x_cont(new : boolean) : boolean
  641. ;   sets the new value for XON/XOFF control and returns the OLD value
  642. ;
  643.     public    x_cont
  644.     assume    ds:nothing
  645. x_cont    proc    far
  646.     push    bp
  647.     mov    bp,sp
  648.     xor    ax,ax        ;set to FALSE
  649.     cli
  650.     .ifs    flags,f_xcont
  651.         inc     ax            ;set to TRUE
  652.     .endif
  653.     and    flags,not f_xcont    ;clear the flag
  654.     .if    <byte ptr [bp+6]> ne 0
  655.         or        flags,f_xcont
  656.     .endif
  657.     sti
  658.     pop    bp
  659.     ret    2
  660. x_cont    endp
  661.  
  662.  
  663. ;---------------------------------------
  664. ;  procedure clearterm;
  665. ;    Clear the interrupt so stray data will not kill the system
  666. ;---------------------------------------
  667.     public    clearterm
  668. clearterm proc    far
  669.     mov    bx,com_base
  670.     lea    dx,mcr        ; MCR
  671.     in    al,dx
  672.     and    al,not 1000B    ; clear interrupt control bit
  673.     out    dx,al
  674.     lea    dx,ier        ; IER
  675.     xor    al,al
  676.     out    dx,al        ; clear all interrupts
  677.     ret
  678. clearterm endp
  679.  
  680. ;---------------------------------------
  681. ; procedure dropline
  682. ;
  683. ;    'drop' the communications line
  684. ;---------------------------------------
  685.     public    dropline
  686. dropline proc far
  687.     mov    bx,com_base
  688.     lea    dx,mcr
  689.     in    al,dx
  690.     and    al,0f0H     ; clear the DTR and interrupt flags
  691.     out    dx,al
  692.     ret
  693. dropline endp
  694.  
  695. ;---------------------------------------
  696. ; toggle TR  -- for VENTEL autodialler
  697. ;---------------------------------------
  698.     public    toggle_tr
  699.  
  700. toggle_tr proc far
  701.     mov    bx,com_base
  702.     xor    ax,ax
  703.     mov    es,ax        ; set ES to low memory
  704.     lea    dx,mcr
  705.     in    al,dx
  706.     push    ax        ; save original value
  707.     and    al,0fcH     ; clear the DTR and interrupt flags
  708.     out    dx,al
  709.     mov    ax,timer_low
  710.     .repeat
  711.         mov     cx,timer_low
  712.         sub     cx,ax
  713.     .until    cx ae 18    ; wait 1 second
  714.     pop    ax        ; retrieve original value
  715.     out    dx,al
  716.     ret
  717. toggle_tr endp
  718.  
  719. ;---------------------------------------
  720. ; function modem_status : byte;
  721. ;
  722. ;    returns the contents of the modem status register
  723. ;---------------------------------------
  724.     public    modem_status
  725. modem_status proc    far
  726.     mov    bx,com_base
  727.     lea    dx,msr
  728.     in    al,dx
  729.     ret
  730. modem_status endp
  731.  
  732. ;---------------------------------------
  733. ; procedure clear_comm
  734. ;
  735. ; this resets the comm software. Will hopefully unlock any `funny' conditions
  736. ;---------------------------------------
  737.  
  738.     assume    ds:nothing
  739.     public    clear_comm
  740. clear_comm proc far
  741.     cli                ; lockout interrupts
  742.     and    flags,f_xcont        ; leave the XON/XOFF set correctly
  743.     mov    r_length,0
  744.     mov    r_index,offset r_buff
  745.     sti
  746.     ret
  747. clear_comm endp
  748.  
  749.  
  750. ;---------------------------------------
  751. ; procedure set_interrupt_high(number:integer);
  752. ;
  753. ; This causes the communications port to have the highest priority so
  754. ; that data overruns do not occur.
  755. ;---------------------------------------
  756.     assume    ds:nothing
  757.     public    set_interrupt_high
  758. set_interrupt_high proc far
  759.     push    bp    
  760.     mov    bp,sp
  761.     mov    al,[bp+6]        ; pick up the interrupt level
  762.     add    al,0C0H-1        ; setup the opcode for the 8259
  763.     out    20H,al            ; do the operation    
  764.     pop    bp
  765.     ret    2
  766. set_interrupt_high endp
  767.  
  768. Communications    ENDS
  769.  
  770.     check$
  771.     END
  772.